package com.jx.mlxg.service.impl;

import com.jx.mlxg.entity.Orders;
import com.jx.mlxg.entity.PaymentRequest;
import com.jx.mlxg.mapper.OrdersMapper;
import com.jx.mlxg.service.PaymentService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import org.dom4j.Document;
import org.dom4j.Element;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class PaymentServiceImpl implements PaymentService {

    @Value("${wxpay.app-id}")
    private String appId;

    @Value("${wxpay.mch-id}")
    private String mchId;

    @Value("${wxpay.mch-key}")
    private String mchKey;

    @Value("${wxpay.notify-url}")
    private String notifyUrl;

    @Value("${wxpay.api-url}")
    private String apiUrl;

    private final OrdersMapper ordersMapper;

    @Override
    @Transactional
    public Map<String, String> createJsapiPayment(PaymentRequest request) {
        Orders order = createPaymentOrder(request);
        Map<String, String> params = buildBaseParams(request, order);
        params.put("sign", generateSignature(params));

        String xmlResult = postToWechat(apiUrl, mapToXml(params));
        Map<String, String> result = parseXml(xmlResult);

        if ("FAIL".equals(result.get("return_code"))) {
            throw new RuntimeException("微信支付创建失败: " + result.get("return_msg"));
        }

        return buildClientParams(result.get("prepay_id"));
    }

    @Override
    @Transactional
    public String handlePaymentCallback(HttpServletRequest request) {
        try {
            String xml = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
            Map<String, String> result = parseXml(xml);

            if (!verifySignature(result)) {
                return errorResponse("签名验证失败");
            }

            if ("SUCCESS".equals(result.get("return_code"))) {
                handleSuccessfulPayment(result);
                return successResponse();
            }
            return errorResponse(result.get("return_msg"));
        } catch (Exception e) {
            log.error("支付回调处理异常", e);
            return errorResponse("系统异常");
        }
    }

    private Orders createPaymentOrder(PaymentRequest request) {
        Orders order = new Orders();
//        order.setOrderId(request.getOrderId());
//        order.setAmount(request.getAmount());
//        order.setOpenid(request.getOpenid());
//        order.setStatus(0);
//        order.setCreateTime(LocalDateTime.now());
//        paymentOrderMapper.insert(order);
        return order;
    }

    private Map<String, String> buildBaseParams(PaymentRequest request, Orders order) {
        Map<String, String> params = new TreeMap<>();
        params.put("appid", appId);
        params.put("mch_id", mchId);
        params.put("nonce_str", generateNonceStr());
        params.put("body", request.getDescription());
        params.put("out_trade_no", order.getOrderId());
        params.put("total_fee", request.getAmount().multiply(BigDecimal.valueOf(100)).intValue() + "");
        params.put("spbill_create_ip", "127.0.0.1");
        params.put("notify_url", notifyUrl);
        params.put("trade_type", "JSAPI");
        params.put("openid", request.getOpenid());
        return params;
    }

    private String generateSignature(Map<String, String> params) {
        try {
            String stringA = params.entrySet().stream()
                    .filter(e -> !e.getValue().isEmpty())
                    .map(e -> e.getKey() + "=" + e.getValue())
                    .collect(Collectors.joining("&"));

            String stringSignTemp = stringA + "&key=" + mchKey;
            return DigestUtils.md5Hex(stringSignTemp).toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    private Map<String, String> buildClientParams(String prepayId) {
        Map<String, String> params = new TreeMap<>();
        params.put("appId", appId);
        params.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("nonceStr", generateNonceStr());
        params.put("package", "prepay_id=" + prepayId);
        params.put("signType", "MD5");
        params.put("paySign", generateSignature(params));
        return params;
    }

    private void handleSuccessfulPayment(Map<String, String> result) {
        Orders order = ordersMapper.selectById(result.get("out_trade_no"));
//        order.setStatus(1);
//        order.setTransactionId(result.get("transaction_id"));
//        order.setPayTime(LocalDateTime.now());
        ordersMapper.updateById(order);
    }

    private static String generateNonceStr() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 32);
    }

    private static String mapToXml(Map<String, String> params) {
        StringBuilder xml = new StringBuilder("<xml>");
        params.forEach((k, v) -> xml.append("<").append(k).append(">").append(v).append("</").append(k).append(">"));
        return xml.append("</xml>").toString();
    }

    private static Map<String, String> parseXml(String xml) {
        try {
            Map<String, String> map = new HashMap<>();
            Document document = (Document) DocumentHelper.parseText(xml);
            Element root = document.getRootElement();
            for (Iterator<Element> it = root.elementIterator(); it.hasNext();) {
                Element element = it.next();
                map.put(element.getName(), element.getText());
            }
            return map;
        } catch (DocumentException e) {
            throw new RuntimeException("XML解析失败", e);
        }
    }

    private String postToWechat(String url, String xmlData) {
        try {
            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/xml");

            try (OutputStream os = conn.getOutputStream()) {
                os.write(xmlData.getBytes(StandardCharsets.UTF_8));
            }

            try (InputStream is = conn.getInputStream()) {
                return IOUtils.toString(is, StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            throw new RuntimeException("微信接口请求失败", e);
        }
    }

    private boolean verifySignature(Map<String, String> params) {
        String receivedSign = params.remove("sign");
        String calculatedSign = generateSignature(params);
        return receivedSign.equals(calculatedSign);
    }

    private String successResponse() {
        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    private String errorResponse(String msg) {
        return String.format("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[%s]]></return_msg></xml>", msg);
    }
}